!pr3
Toggling Between Two Values.....................Jan Eugenides

In the course of my job as Technical Editor for MicroSPARC, Inc. (the publishers of Nibble and Nibble Mac magazines), I am often called upon to modify programs that we are going to publish to make them compatible with configurations other than the one the author originally wrote for.  Recently, I had to change a program to toggle between Drive 1 and Drive 3, rather than Drive ! and Drive 2 as it was originally coded.  Here is the original subroutine which toggled the drive number stored in a variable named CD:

       TOGGLE.DRIVE
               LDA CD
               CMP #1
               BEQ .1
               LDA #1
               STA CD
               BNE .2
       .1      INC CD
       .2      RTS
       CD      .BS 1

This code takes a total of 19 bytes, including the variable CD.  My task was to exactly replace this routine with one which would toggle between 1 and 3 rather than 1 and 2.  It had to use the same number of bytes, or less.  It looks easy enough, but I couldn't come up with a solution.  All my routines required one or two more bytes.  I finally took the easy way out and patched it with a JMP to a free space near the end of the program, and put my code there.  It works, but is there a shorter way?

Bob, you are the best code squeezer around, so I thought I'd give the problem to you.  You'll undoubtedly come up with some sneaky code that does the trick in three bytes or less!


An Answer for Jan.........................Bob Sander-Cederlof

I don't know if I am the best code squeezer or not, but I can't squeeze it all the way to three bytes!  My best attempt is nine bytes:

       TOGGLE.DRIVE
               LDA #1
       CD      .EQ *-1
               EOR #2
               STA CD
               RTS

In general, you can toggle back and forth between any two values by using the EOR instruction.  The toggle constant is simply the exclusive-or of the two values.  For example, to toggle back and forth between the values $A0 and $B2, I would use "EOR #$12".

My subroutine changes 1 to 3 and 3 to 1, as you requested.  However, it is not functionally identical to the original code.  The original code did not store the variable CD inside an immediate-mode LDA, as I did.  If that troubles you, simply change that line to "LDA CD" and add the line "CD .BS 1" at the end.  The result takes ten bytes, still well under the limit.

The original code also always had the side-effect of setting carry status, so you might need to add a "SEC" instruction.  I doubt it, because the original code would be very weird if it depended on this side-effect.

The original code not only changed 3 to 1, but also changed any other value not already 1 into 1.  This is also probably not a necessary feature, because prior code should have made sure that we started with a valid drive number.

I came up with several other approaches to the problem, all of which are shorter than the original subroutine:

       TOGGLE.DRIVE
               LSR CD     3 TO 1, OR 1 TO 0
               BNE .1     IT WAS 3 TO 1
               LDA #3     CHANGE 1 TO 3
               STA CD
       .1      RTS

       TOGGLE.DRIVE
               CLC
               LDA CD
               ADC #2     1 TO 3, OR 3 TO 5
               AND #3     5 TO 1
               RTS

None of these are particularly tricky or sneaky.  In fact, the first and shortest one is the most straightforward.  What would be tricky or sneaky is if the original author depended on the hidden side-effects in his subroutine.
